
#include <malloc.h>
#include <unistd.h>

#include "ordenamiento-final.h"

#include "../varios/log.h"
#include "../varios/mensajes.h"
#include "../varios/mpi-utiles.h"
#include "../varios/compresion.h"

#include "../../compartido/vectores.h"



/*
 * Junta 2 vectores remotos leidos de los pipes pasados por parametro
 */
struct VECTOR *recibirOrdenarUltimosVectores(int *nodosFinales, long long *tamNodosFinales) {
    
    int idNodo1 = nodosFinales[0];
    int idNodo2 = nodosFinales[1];
    long long tamVector1 = tamNodosFinales[0];
    long long tamVector2 = tamNodosFinales[1];

    LOGGER("Juntamos un vector de tam %l, leido del nodo %d, con otro vector de tam %l, leido del nodo %d",
            tamVector1, idNodo1, tamVector2, idNodo2);
    
    // Creamos el vector resultante
    long long tamTotal = tamVector1 + tamVector2;
    struct VECTOR *vectorResultante = crearVector(tamTotal);
    
    // Creamos los vectores que recibiremos
    int *bufferVector1 = NULL;
    int *bufferVector2 = NULL;
        
    // Indice que apuntará al próximo posición a escribir en el vector resultante
    long long indiceResultante = 0;
    
    // Indican el proximo elemento a comparar de los vectores 1 y 2
    long long offsetBufferVector1 = 0;
    long long offsetBufferVector2 = 0;
    
    // Indican el offset total de los vectores
    long long offsetTotalVector1 = 0;
    long long offsetTotalVector2 = 0;
    
    // Ultimo elemento cargado de cada vector
    long long ultimoElemCargVector1 = -1;
    long long ultimoElemCargVector2 = -1;
    
    // Cuando se hayan leido todos los elementos remotos y se ordenen, se saldra del bucle
    while (indiceResultante<tamTotal) {
        
        // Esperamos a que lleguen mas elementos del vector 1 si es necesario
        if (offsetTotalVector1>ultimoElemCargVector1 && offsetTotalVector1<tamVector1) {
            
            LOGGER("Cargamos elementos remotos del vector 1. Ultimo elemento cargado: %l", ultimoElemCargVector1);
            
            if (bufferVector1 != NULL) {
                free(bufferVector1);
            }
            
            struct DATOS_RECIBIDOS recepcion = recibirDatos(idNodo1, MSG_VECTOR_FINAL);
            struct DATOS_DESCOMPRIMIDOS descomp = descomprimir(recepcion.datos);
            free(recepcion.datos);
            bufferVector1 = (int *)descomp.datos;
            
            offsetBufferVector1 = 0;
            ultimoElemCargVector1 += descomp.longitud/sizeof(int);
            
            LOGGER("Vector obtenido: %s", imprimirBloqueInt(bufferVector1, descomp.longitud/sizeof(int)));
            
        }
        
        // Esperamos a que lleguen mas elementos del vector 2 si es necesario
        if (offsetTotalVector2>ultimoElemCargVector2 && offsetTotalVector2<tamVector2) {
            
            LOGGER("Cargamos elementos remotos del vector 2. Ultimo elemento cargado: %l", ultimoElemCargVector2);
            
            if (bufferVector2 != NULL) {
                free(bufferVector2);
            }
            
            struct DATOS_RECIBIDOS recepcion = recibirDatos(idNodo2, MSG_VECTOR_FINAL);
            struct DATOS_DESCOMPRIMIDOS descomp = descomprimir(recepcion.datos);
            free(recepcion.datos);
            bufferVector2 = (int *)descomp.datos;
            
            offsetBufferVector2 = 0;
            ultimoElemCargVector2 += descomp.longitud/sizeof(int);
            
            LOGGER("Vector obtenido: %s", imprimirBloqueInt(bufferVector2, descomp.longitud/sizeof(int)));
            
        }
        
        if (offsetTotalVector1==tamVector1) {
            LOGGER("Se agoto el vector 1");
            escribirValor(vectorResultante, bufferVector2[offsetBufferVector2], indiceResultante);
            offsetBufferVector2++;
            offsetTotalVector2++;
        } else if (offsetTotalVector2==tamVector2) { // Lo mismo para el vector 2
            LOGGER("Se agoto el vector 2");
            escribirValor(vectorResultante, bufferVector1[offsetBufferVector1], indiceResultante);
            offsetBufferVector1++;
            offsetTotalVector1++;
        } else if (bufferVector1[offsetBufferVector1] <= bufferVector2[offsetBufferVector2]) {
            LOGGER("Vector 1 gana: [%l] = %d", offsetBufferVector1, bufferVector1[offsetBufferVector1]);
            escribirValor(vectorResultante, bufferVector1[offsetBufferVector1], indiceResultante);
            offsetBufferVector1++;
            offsetTotalVector1++;
        } else {
            LOGGER("Vector 2 gana: [%l] = %d", offsetBufferVector2, bufferVector2[offsetBufferVector2]);
            escribirValor(vectorResultante, bufferVector2[offsetBufferVector2], indiceResultante);
            offsetBufferVector2++;
            offsetTotalVector2++;
        }
        
        indiceResultante++;
        
    }

    
    // Liberamos memoria
    free(bufferVector1);
    free(bufferVector2);
    
    return vectorResultante;
    
}
